001 /* 002 * Copyright 2004 Niclas Hedhman 003 * Copyright 2004-2006 Stephen J. McConnell 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 014 * implied. 015 * 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019 020 package net.dpml.transit.artifact; 021 022 import java.io.InputStream; 023 import java.io.IOException; 024 import java.io.OutputStream; 025 import java.io.File; 026 import java.net.UnknownServiceException; 027 import java.net.URI; 028 import java.net.URL; 029 import java.net.URLConnection; 030 import java.net.URISyntaxException; 031 032 import net.dpml.transit.Artifact; 033 import net.dpml.transit.Transit; 034 import net.dpml.transit.SecuredTransitContext; 035 import net.dpml.transit.CacheHandler; 036 037 import net.dpml.lang.Part; 038 039 import net.dpml.util.MimeTypeHandler; 040 041 /** 042 * The connection handler for URLs based on the "artifact" protocol family. 043 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 044 * @version 1.0.1 045 */ 046 public class ArtifactURLConnection extends URLConnection 047 { 048 // ------------------------------------------------------------------------ 049 // state 050 // ------------------------------------------------------------------------ 051 052 /** 053 * Transit context. 054 */ 055 private final SecuredTransitContext m_context; 056 057 /** 058 * Artifact. 059 */ 060 private final Artifact m_artifact; 061 062 /** 063 * Reference fragment. 064 */ 065 private final String m_reference; 066 067 /** 068 * The connected state. 069 */ 070 private boolean m_connected; 071 072 // ------------------------------------------------------------------------ 073 // constructor 074 // ------------------------------------------------------------------------ 075 076 /** 077 * Creation of a new handler. 078 * @param url the url to establish a connection with 079 * @param context the transit context 080 * @exception NullPointerException if the url argument is null 081 * @exception IOException if the url argument is invalid 082 */ 083 ArtifactURLConnection( URL url, SecuredTransitContext context ) 084 throws NullPointerException, IOException 085 { 086 super( url ); 087 088 Transit.getInstance(); // make sure Transit is initialized 089 090 m_context = context; 091 m_reference = getReference( url ); 092 093 String spec = getRealSpec( url, m_reference ); 094 try 095 { 096 m_artifact = Artifact.createArtifact( spec ); 097 } 098 catch( URISyntaxException e ) 099 { 100 throw new IOException( e.toString() ); 101 } 102 } 103 104 // ------------------------------------------------------------------------ 105 // URLConnection 106 // ------------------------------------------------------------------------ 107 108 /** 109 * Establish a connection. The implementation will attempt to 110 * resolve the resource relative to the cache and associated hosts. 111 * 112 * @exception IOException is an error occurs while attempting to establish 113 * the connection. 114 */ 115 public void connect() 116 throws IOException 117 { 118 m_connected = true; 119 } 120 121 /** 122 * Return an input stream to the resource. 123 * @return the input stream 124 * @exception IOException is an error occurs 125 */ 126 public InputStream getInputStream() 127 throws IOException 128 { 129 connect(); 130 CacheHandler cache = m_context.getCacheHandler(); 131 if( null != m_reference ) 132 { 133 return cache.getResource( m_artifact, m_reference ); 134 } 135 else 136 { 137 return cache.getResource( m_artifact ); 138 } 139 } 140 141 /** 142 * Return an output stream to the resource. 143 * @return the output stream 144 * @exception IOException if any I/O problems occur. 145 */ 146 public OutputStream getOutputStream() 147 throws IOException 148 { 149 CacheHandler cache = m_context.getCacheHandler(); 150 return cache.createOutputStream( m_artifact ); 151 } 152 153 /** 154 * Reutrn the mimetype of the content. 155 * @return the content mimetype 156 */ 157 public String getContentType() 158 { 159 String type = m_artifact.getType(); 160 return MimeTypeHandler.getMimeType( type ); 161 } 162 163 /** 164 * Return the content for this artifact. 165 * @return the content object (possibly null) 166 * @exception IOException is an error occurs 167 */ 168 public Object getContent() 169 throws IOException 170 { 171 Object content = getContent( new Class[0] ); 172 if( content != null ) 173 { 174 return content; 175 } 176 else 177 { 178 return super.getContent(); 179 } 180 } 181 182 /** 183 * Return the content for this artifact. 184 * @param classes a sequence of classes against which the 185 * implementation will attempt to establish a known match 186 * @return the content object (possibly null) 187 * @exception IOException is an error occurs 188 */ 189 public Object getContent( Class[] classes ) 190 throws IOException 191 { 192 193 // 194 // attempt to resolve this locally as we may be dealing 195 // with Depot references to the artifact File 196 // 197 198 for( int i=0; i < classes.length; i++ ) 199 { 200 Class c = classes[i]; 201 if( c.equals( File.class ) ) 202 { 203 return m_context.getCacheHandler().getLocalFile( m_artifact ); 204 } 205 } 206 207 String type = m_artifact.getType(); 208 209 // 210 // if the type is a plugin then handle this directly 211 // 212 213 if( "part".equals( type ) ) 214 { 215 URI uri = m_artifact.toURI(); 216 Part part = Part.load( uri ); 217 return part.getContent( classes ); 218 } 219 220 // 221 // otherwise fallback on the default jvm content handling 222 // 223 224 try 225 { 226 Object content = super.getContent( classes ); 227 if( content != null ) 228 { 229 return content; 230 } 231 } 232 catch( UnknownServiceException use ) 233 { 234 boolean ignoreThis = true; 235 } 236 237 return null; 238 } 239 240 // ------------------------------------------------------------------------ 241 // implementation 242 // ------------------------------------------------------------------------ 243 244 /** 245 * Return a fragment referencing content within the resource referenced by 246 * the artifact. 247 * @param url the url 248 * @return the fragment or null if this is not a referential url 249 */ 250 private String getReference( URL url ) 251 { 252 String path = url.getPath(); 253 int i = path.indexOf( '!' ); 254 if( i < 0 ) 255 { 256 return null; 257 } 258 else 259 { 260 return path.substring( i ); 261 } 262 } 263 264 /** 265 * Return the real specification of the supplied url. 266 * @param url the url to evaluate 267 * @param ref a reference fragment 268 * @return the artifact url spec withough the ref fragment 269 */ 270 private String getRealSpec( URL url, String ref ) 271 { 272 if( null != ref ) 273 { 274 String spec = url.toString(); 275 int j = spec.indexOf( ref ); 276 if( j > 0 ) 277 { 278 String s = spec.substring( 0, j ); 279 String version = url.getUserInfo(); 280 if( null != version ) 281 { 282 s = s + "#" + version; 283 } 284 return s; 285 } 286 } 287 return url.toString(); 288 } 289 }